Data binding 強化了 XML 在 project 裡的功能和地位,讓元件可以在 XML 就綁上點擊事件、資料等等。
在開始進行 data binding 以前,要先設定環境。
首先是在 Gradle(Module:app)加上以下
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
android {
    buildFeatures {
        dataBinding true
    }
}
dependencies {
    kapt "com.android.databinding:compiler:3.1.4"
}
跟 Gradle(Project: ProjectName)
buildscript {
    ext.kotlin_version = "1.4.10"
    dependencies {
        classpath "com.android.tools.build:gradle:4.0.2"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}
在 data binding 時,會跟 view model 有比較大的關連,所以先講 view model。
這次我的資料只有放在 view model 裡面了。
class MainViewModel: ViewModel(){
    var data= ObservableField<String>("")
    init {
        data.set("init")
    }
    fun btnClick(){
        data.set("clicked!")
    }
}
裡面有一個資料跟方法
Observable 是給 view model 用的型態,跟之前講的 live data 有點類似,可以用 getter and setter 取值給值。
一個 text view 一個 edit view 一個 button
data binding 要在最外面加上 layout 包起來,記得把 xmlns 的屬性也移進去。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable
            name="viewModel"
            type="com.example.mvvm.ui.main.MainViewModel"/>
    </data>
<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.main.MainActivity">
    
     <TextView
        android:id="@+id/textMainResult"
        android:text="@{viewModel.data}"
        android:textSize="30sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toTopOf="@id/editMain"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>
        
    <EditText
        android:id="@+id/editMain"
        android:gravity="center"
        android:text="@={viewModel.data}"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintVertical_bias="0.3" />
        
    <Button
        android:id="@+id/btnMainResult"
        android:text="result"
        android:onClick="@{() -> viewModel.btnClick()}"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/editMain"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintVertical_bias="0.2"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
可以發現除了外面的 layout 以外,跟一般的 XML 前面還多了 data 的標籤。那是 XML 的資料來源,通常會丟 view model 近來,這樣就可以把 view model 裡的東西丟給各元件了。
從 text view 的 text 屬性可以看到,他是利用"@{viewmodel.你要的ObservableField成員}" 進行 data binding。
如果想要可以改變 binding 的值,要在 @ 跟 { } 之間加上等號,這樣就代表可以雙向改變此資料,例如 edit text,在打入字的時候,data 也會跟著改變。
按鈕則可以在 onClick 屬性加上方法,套用上 "@{() -> 你要的方法}"。
class MainActivity : AppCompatActivity() {
    private val viewModel: MainViewModel by lazy {
        ViewModelProvider(this, MyViewModelFactory()).get(MainViewModel::class.java)
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        
        // binding.viewModel 是 XML <data> 裡的那個
        binding.viewModel = viewModel
    }
}
個人覺得 data binding 最舒服的地方就是 activity 不用再加上一大堆的 findViewById。
只要加上 binding 跟 設置 viewModel。
中間的 ActivityMainBinding 不是我宣告的,做好以後 build 成功會自動出現。
打入 edit text
按下按鈕
在最後寫個筆者認為的 data binding 的缺點,就是不方便 debug。
每次有地方寫錯,它只會跟你說 ActivityMainBindingImpl 出錯誤了,留下一模一樣的東西,實在是有點難搞。
筆者之後就都還是做成 LiveData 了 :|